A WebSocket connection is closed properly by calling the close() method with an optional status code and reason, which initiates the closing handshake, followed by handling the close event to confirm cleanup and optionally implement reconnection logic.
Closing a WebSocket connection properly involves more than just terminating the TCP socket. The WebSocket protocol includes a closing handshake where both sides exchange close frames to ensure all messages are delivered and resources are cleaned up gracefully. In JavaScript, this is initiated by calling the close() method on the WebSocket object. The connection then transitions through the CLOSING state to CLOSED, and a close event is fired with details about the closure. Proper closure prevents resource leaks, ensures any remaining messages are processed, and provides opportunities for reconnection logic.
code (optional): A numeric status code explaining why the connection is closing. Must be either 1000 (normal closure) or in the range 3000-4999 for application-specific codes .
reason (optional): A human-readable string explaining the reason for closure. Maximum length is 123 bytes (UTF-8 encoded) .
No parameters: socket.close() uses default code 1000 and empty reason, indicating normal closure .
The close event provides crucial information about how the connection ended. The wasClean property indicates whether the closure was initiated by a proper close handshake (true) or happened unexpectedly due to network failure, timeout, or error (false). The code and reason provide additional context. This information is essential for deciding whether to attempt reconnection and how to report errors to users.
1000 - Normal Closure: The connection successfully completed its purpose and closed normally .
1001 - Going Away: Server is shutting down or client navigated away (tab closed) .
1002 - Protocol Error: Terminating due to a protocol error .
1003 - Unsupported Data: Received data type that cannot be accepted .
1005 - No Status Received: Close event fired but no close code provided (internal use) .
1006 - Abnormal Closure: Connection closed abnormally without a close frame (network failure) .
1009 - Message Too Big: Frame too large to process .
1011 - Internal Error: Server encountered an unexpected condition .
1015 - TLS Failure: TLS handshake failed (can't be used from JavaScript) .
3000-3999 - Library/Application codes: Reserved for libraries and frameworks .
4000-4999 - Private use codes: For application-specific purposes .
One critical aspect of proper closure is ensuring you don't attempt to close a connection that's already closing or closed. Checking the readyState before calling close() prevents errors. Additionally, after calling close(), you should not attempt to send more messages—they will fail or be queued incorrectly. The connection moves to CLOSING state immediately, and any further send attempts will throw an error.
In Node.js environments using the 'ws' library, there's an additional method: terminate(). Unlike close(), which performs the closing handshake, terminate() immediately destroys the socket without waiting for the handshake. This should only be used when you need to force-close a connection that's stuck or when the application is shutting down abruptly. The close event will still fire, but wasClean will be false and the code will likely be 1006.
Proper WebSocket closure is about respecting the protocol's handshake, cleaning up resources, and providing good user experience. By using appropriate close codes, checking ready states, and implementing intelligent reconnection logic based on close event data, you can build WebSocket applications that handle network disruptions gracefully and maintain connection hygiene. The close event's code and reason are your primary tools for understanding why a connection ended and deciding what to do next.